package com.gitee.apanlh.util.random;

import com.gitee.apanlh.util.valid.Assert;

import java.security.SecureRandom;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 	生成随机工具类
 * 	<br>支持使用线程本地随机数和安全随机数
 * 	<br>可生成不同范围的随机数和随机字节数组
 * 	<br>适用于加密、安全、测试数据生成等场景
 * 
 * 	@author Pan
 */
public class RandomUtils {
	
	/**
	 * 	构造函数
	 * 
	 * 	@author Pan
	 */
	private RandomUtils() {
		//	不允许外部实例
		super();
	}
	
	/**	
	 * 	获取当前线程ThreadLocalRandom实例，用于生成随机数
	 * 	<br>提供了高效的随机数生成器，每个线程都有一个独立的实例
	 * 	<br>由于每个线程都有独立的实例，因此不会出现线程安全问题
	 * 	
	 * 	@author Pan
	 * 	@return	ThreadLocalRandom
	 */
	public static ThreadLocalRandom getRandomOfThread() {
		return ThreadLocalRandom.current();
	}
	
	/**	
	 * 	返回一个提供安全随机数的 SecureRandom
	 * 	<br>强随机数生成器,提供了安全性较高的随机数生成功能
	 * 	<br>它使用了密集种子生成器和可预测性保护机制，以提供高质量的随机数
	 *  <br>适用于需要更高安全性的随机数生成场景
	 *  	
	 * 	@author Pan
	 * 	@return	SecureRandom
	 */
	public static SecureRandom getRandomOfSecure() {
		return new SecureRandom();
	}
	
	/**	
	 * 	返回一个提供安全随机数的 SecureRandom
	 * 	<br>自定义随机数种子
	 * 	<br>强随机数生成器,提供了安全性较高的随机数生成功能
	 * 	<br>它使用了密集种子生成器和可预测性保护机制，以提供高质量的随机数
	 *  <br>适用于需要更高安全性的随机数生成场景
	 *  	
	 * 	@author Pan
	 * 	@param 	seed	随机数种子
	 * 	@return	SecureRandom
	 */
	public static SecureRandom getRandomOfSecure(byte[] seed) {
		if (seed == null) {
			return getRandomOfSecure();
		}
		return new SecureRandom(seed);
	}
	
	/**	
	 * 	指定某一个范围内随机数
	 * 	注意：例如指定范围为1，随机数会出现1本身，即范围为0-1
	 * 	
	 * 	@author Pan
	 * 	@param 	range	范围值(包含本身数)
	 * 	@return	long
	 */
	public static long randomLong(long range) {
		Assert.isFalse(range < 0, "range must not be less than 0");
		return getRandomOfThread().nextLong(0, range + 1L);
	}
	
	/**	
	 * 	指定某一个范围内随机数
	 * 	<br>指定起始及结束范围值
	 * 	注意：例如指定范围为0, 1，随机数会出现1本身，即范围为0-1
	 * 	
	 * 	@author Pan
	 * 	@param 	range	范围值(包含本身数)
	 * 	@param 	toRange	至范围值(包含本身数)
	 * 	@return	long
	 */
	public static long randomLong(long range, long toRange) {
		Assert.isFalse(range < 0 || toRange < range, "range must not be less than 0 or toRange is less than range");
		return getRandomOfThread().nextLong(range, toRange + 1L);
	}

	/**	
	 * 	指定某一个范围内随机数
	 * 	注意：例如指定范围为1，随机数会出现1本身，即范围为0-1
	 * 	
	 * 	@author Pan
	 * 	@param 	range	范围值(包含本身数)
	 * 	@return	long
	 */
	public static int randomInt(int range) {
		Assert.isFalse(range < 0, "range must not be less than 0");
		return getRandomOfThread().nextInt(0, range + 1);
	}
	
	/**	
	 * 	指定某一个范围内随机数
	 * 	<br>指定起始及结束范围值
	 * 	注意：例如指定范围为0, 1，随机数会出现1本身，即范围为0-1
	 * 	
	 * 	@author Pan
	 * 	@param 	range	范围值(包含本身数)
	 * 	@param 	toRange	至范围值(包含本身数)
	 * 	@return	long
	 */
	public static int randomInt(int range, int toRange) {
		Assert.isFalse(range < 0 || toRange < range, "range must not be less than 0 or toRange is less than range");
		return getRandomOfThread().nextInt(range, toRange + 1);
	}
	
	/**	
	 * 	生成随机字节数组
	 * 	<br>加密和安全(随机字节数组可用于生成密钥、初始化向量（IV）或盐等加密和安全操作中所需的随机数据) 16字节（128位）、24字节（192位）、32字节（256位）
	 * 	<br>随机数生成(通过将字节数组转换为整数或其他数据类型，可以生成具有所需范围或特定分布的随机数)
	 * 	<br>默认使用线程随机器
	 * 	<br>自定义长度
	 * 	
	 * 	@author Pan
	 * 	@param 	length		长度为 16（128 位）、24（192 位）、32（256 位）
	 * 	@return	byte[]
	 */	
	public static byte[] randomBytes(int length) {
		return randomBytes(length, false);
	}
	
	/**	
	 * 	生成随机字节数组
	 * 	<br>加密和安全(随机字节数组可用于生成密钥、初始化向量（IV）或盐等加密和安全操作中所需的随机数据) 16字节（128位）、24字节（192位）、32字节（256位）
	 * 	<br>随机数生成(通过将字节数组转换为整数或其他数据类型，可以生成具有所需范围或特定分布的随机数)
	 * 	<br>自定义长度
	 * 	<br>自定义随机器
	 * 	
	 * 	@author Pan
	 * 	@param 	length		长度为 16（128 位）、24（192 位）、32（256 位）
	 * 	@param 	isSecure	是否使用强随机数，如果为 true，则使用强随机数生成器；如果为 false，则使用线程安全的伪随机数生成器
	 * 	@return	byte[]
	 */	
	public static byte[] randomBytes(int length, boolean isSecure) {
		byte[] randomBytes = new byte[length];
		
		if (isSecure) {
			getRandomOfSecure().nextBytes(randomBytes);
		} else {
			getRandomOfThread().nextBytes(randomBytes);
		}
		return randomBytes;
	}
	
	/**	
	 * 	生成随机布尔值(true/false)
	 * 	<br>用于生成true(1)或false(0)
	 * 	
	 * 	@author Pan
	 * 	@return	boolean
	 */
	public static boolean randomBoolean() {
		return randomInt(0, 1) == 1;
	}
}
